<?php
/**
 * Short description for posts_controller.php
 *
 * @copyright     Copyright (c) 2009, Miha Nahtigal
 * @link          http://www.nahtigal.com/
 * @package       lil_blogs_plugin
 * @subpackage    lil_blogs_plugin.controllers
 * @license       http://www.opensource.org/licenses/mit-license.php The MIT License
 */
/**
 * PostsController class
 *
 * @uses          LilBlogsAppController
 * @package       lil_blogs_plugin
 * @subpackage    lil_blogs_plugin.controllers
 */
class PostsController extends LilBlogsAppController {
/**
 * name property
 *
 * @var string 'Posts'
 * @access public
 */
	var $name = 'Posts';
/**
 * paginate property
 *
 * @var array
 * @access public
 */
	var $paginate = array('limit' => 25);
/**
 * uses property
 *
 * @var array
 * @access public
 */
	var $uses = array('LilBlogs.Post', 'LilBlogs.Category', 'Lil.User', 'Lil.Area', 'Paginator');
/**
 * helpers property
 *
 * @var array
 * @access public
 */
	var $helpers = array('LilBlogs.LilBlogs', 'Lil.LilDate');
/**
 * beforeFilter method
 *
 * @access public
 * @return void
 */
	function beforeFilter() {
		$this->Auth->allow('index', 'view');
		
		// disable CSRF protection for comments
		if (($this->params['action'] == 'view') && isset($this->Security)) {
			$this->Security->validatePost = false;
		}
		
		parent::beforeFilter();
	}
/**
 * isAuthorized method
 *
 * @access public
 * @return bool
 */
	function isAuthorized() {
		if (!parent::isAuthorized()) return false;
		
		// plugins can also change authorization
		if (method_exists($this, 'callPluginHandlers')) {
			$c = $this->callPluginHandlers('isAuthorizedPosts', array('return' => true, 'continue' => true));
			if (!isset($c['return']) || $c['return'] == false) return false;
		}
		
		// plugin can determine if it wants to end authorization check
		if (!isset($c['continue']) || $c['continue'] == true) {
			if (in_array($this->params['action'], array('index', 'view'))) return true;

			if (isset($this->Auth) && !Configure::read('Lil.allowUsersAnything')) {
				if (!empty($this->params['admin']) && !$this->currentUser->get()) return false;
				
				if (in_array($this->params['action'], array('admin_edit', 'admin_delete'))) {
					// get selected blog_id
					if ($blog_id = $this->currentArea->get('id')) {
						// check target post's id
						if (empty($this->params['pass'][0])) {
							if (($this->params['action'] != 'admin_edit') || !Configure::read('LilBlogs.allowEmptyBlog')) {
								return false;
							}
						} else {
							// read posts's blog_id
							if (!$posts_blog_id = $this->Post->field('blog_id',
								array('Post.id' => $this->params['pass'][0])))
							{
								return false;
							}
		
							// check if post belongs to current blog
							if ($posts_blog_id != $blog_id) return false;
						}
					
					} else {
						// there is no selected blog
						if (!Configure::read('LilBlogs.allowEmptyBlog')) return false;
					}

				} else if ($this->params['admin']) {
					if (!$blog_id = $this->currentArea->get('id')) {
						if (!Configure::read('LilBlogs.allowEmptyBlog')) return false;
					}
				}
				
				// test if user has rights to current blog
				return
					Configure::read('Lil.noAreas') ||
					$this->currentUser->role('admin') ||
					$this->currentUser->canAccessArea($this->currentUser->get('id'), $blog_id);
			}
		}
		return true;
	}
/**
 * beforeRender method
 *
 * @access public
 * @return void
 */
	function beforeRender() {
		// determine theme
		if (!empty($this->params['named']['theme_preview'])) {
			$this->theme = $this->params['named']['theme_preview'];
		} else {
			if ($blogslug = $this->_extractBlog()) {
				if ($blogs = Configure::read('Lil.noAreas')) {
					if (is_array($blogs)) {
						foreach ($blogs as $blog) {
							$slug_field = Configure::read('LilBlogs.blogSlugField');
							if ($blog['Area'][$slug_field] == $blogslug && !empty($blog['Area']['theme'])) {
								$this->theme = $blog['Blog']['theme'];
							}
						}
					}
				} else if (
					isset($this->Post->Blog) &&
					$this->Post->Blog->hasField('theme') &&
					$theme = $this->Post->Blog->field(
						'theme',
						array('Blog.' . Configure::read('LilBlogs.blogSlugField') => $blogslug)
					)
				) {
					$this->theme = $theme;
				}
			} else if ($theme = Configure::read('LilBlogs.defaultTheme')) {
				$this->theme = $theme;
			}
		}

		parent::beforeRender();
	}
/**
 * index method
 *
 * @access public
 * @return bool
 */
	function index() {
		// extract blog data from params
		$blog_name = $this->_extractBlog();
		$blog_id = $this->_extractBlogId();
		
		// check if blog's ok
		$blog = null;
		if (isset($this->Area) && !(($blog_name && $blog = $this->Area->findByShortName($blog_name)) || 
			($blog_id && $blog = $this->Area->findById($blog_id))))
		{
			return $this->error404();
		}
		
		if (($this->params['blog'] != 'all') && !Configure::read('LilBlogs.allowEmptyBlog')) {
			return $this->error404();
		}
		
		// apply seatch criterio
		$search = false;
		$params = array(
			'conditions'=> array(
				'Post.status >'  => 0
			),
			'limit'     => ($lmt = Configure::read('LilBlogs.mainPageItems')) ? $lmt : 10,
			'order'     => 'Post.created DESC',
		);
		
		// search
		$criterio = '';
		if (!empty($this->data['Post']['criterio'])) $criterio = $this->data['Post']['criterio'];
		
		if (!empty($criterio)) {
			if ($this->Post->lilSearchEnabled()) {
				$params['conditions']['Post.id'] = 
					$this->Post->lilSearch($criterio);
				unset($params['order']);
				unset($params['limit']);
			} else {
				$params['conditions']['OR'] = array(
					'Post.title LIKE' => '%' . $criterio . '%',
					'Post.body LIKE'  => '%' . $criterio . '%',
				);
			}
			$search['criterio'] = $criterio;
		}
		
		
		// filter by category
		$category_id = null;
		if (!empty($this->params['named']['category'])) $category_id = $this->params['named']['category'];
		if (!empty($this->params['url']['filter']['category'])) $category_id = $this->params['url']['filter']['category'];
		
		if (!empty($this->Post->Category) && !empty($category_id))
		{
			$this->Post->bindModel(
				array('hasOne' => array(
					$this->Post->hasAndBelongsToMany['Category']['withClassName'] => array(
						'className' => $this->Post->hasAndBelongsToMany['Category']['with'],
					)
				)), false
			);
			
			$category_alias = 
				$this->Post->hasAndBelongsToMany['Category']['withClassName'] . 
				'.' . 
				$this->Post->hasAndBelongsToMany['Category']['associationForeignKey'];
			
			$params['conditions'][$category_alias] = $category_id;
			$search['category'] = $category_id;
		}
		
		if ($this->params['blog'] == 'all') {
			// show all posts
			$blog_name        = __d('lil_blogs', 'Lil posts', true);
			$blog_description = sprintf(__d('lil_blogs', 'Posts from every single blog on %s', true), Router::url('/', true));
		} else if (empty($blog)) {
			if (!empty($this->params['named']['blog_id'])) {
				$params['conditions']['Post.blog_id'] = $this->params['named']['blog_id'];
			} else {
				$params['conditions']['Post.blog_id'] = null;
			}
			$blog_name        = ($bn = Configure::read('LilBlogs.defaultBlogTitle')) ? $bn : __d('lil_blogs', 'Default Blog', true);
			$blog_description = __d('lil_blogs', 'All posts', true);
		} else {
			// filter posts by blog
			$params['conditions']['Post.blog_id'] = $blog[$this->Area->alias]['id'];
			$blog_name        = $blog[$this->Area->alias]['name'];
			$blog_description = $blog[$this->Area->alias]['description'];
		}
		
		// is it rss?
		if ($this->RequestHandler->prefers('rss') == 'rss') {
			Configure::write('debug', 0);
			$this->set('channel', array(
				'title'       => $blog_name,
				'description' => $blog_description
			));
			$params['limit'] = Configure::read('LilBlogs.rssItems');
		}
		
		$this->paginate = $params;
		$posts = $this->paginate('Post');
		
		// add blog name
		if ($blogs = Configure::read('Lil.noAreas')) {
			foreach ($posts as $k => $p) {
				$posts[$k]['Blog'] = $this->Area->findById($p['Post']['blog_id']);
			}
		} else if (!empty($blog)) {
			foreach ($posts as $k => $p) {
				$posts[$k]['Blog'] = $blog[$this->Area->alias];
			}
		}
		$this->set(compact('blog', 'search', 'posts'));
	}
/**
 * view method
 *
 * @access public
 * @return bool
 */
	function view() {
		$params = array(
			'conditions' => array(
				'Post.status >' => 0,
			),
		);
		
		if (Configure::read('LilBlogs.postBlogField')) {
			$blog_id = $this->_extractBlogId();
			$params['conditions']['Post.' . Configure::read('LilBlogs.postBlogField')] = $blog_id;
		}
		
		$post_id = $this->_extractPost();
		if (is_numeric($post_id) || preg_match('/^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$/i' , $post_id)) {
			$params['conditions']['Post.id'] = $post_id;
		} else {
			$params['conditions']['Post.slug'] = $post_id;
		}
		
		// read post
		if (!$post = $this->Post->find('first', $params)) {
			$this->error404();
			return;
		}
		
		// read comments separately so comment_filter plugin could work
		if (isset($this->Post->Comment))  {
			$comments = $this->Post->Comment->find('all', array(
				'conditions' => array(
					'Comment.post_id' => $post['Post']['id'],
					'Comment.status' => LILCOMMENT_APPROVED
				),
				'recursive'  => -1
			));
			// clean up the HTML of each comment and restructure
			foreach ($comments as $comment) {
				$this->_clean($comment['Comment']);
				$post['Comment'][] = $comment['Comment'];
			}
		}
		
		// read blog if not previously set
		if (isset($this->Post->Blog) && empty($blog)) {
			$blog_params = array(
				'conditions' => array(
					'Blog.id' => $post['Post']['blog_id']
				),
				'contain' => array()
			);
			$blog = $this->Post->Blog->find('first', $blog_params);
		}
		
		$this->set(compact('post', 'blog'));
		
		// save comment
		if (!empty($this->data)) {
			if ($data = $this->Post->Comment->add($this->data)) {
				$data['Comment']['id'] = $this->data['Comment']['id'] = $this->Post->Comment->id;
				if (method_exists($this, 'callPluginHandlers')) {
					$this->callPluginHandlers('after_save_comment', array('data' => $data));
				}
			
				// notify user
				if ($data['Comment']['status'] == LILCOMMENT_APPROVED) {
					$this->Session->setFlash(__d('lil_blogs', 'Your comment has been successfully saved.', true));
				} else {
					$this->Session->setFlash(__d('lil_blogs', 'Your comment has gone into moderation.', true));
				}
			
				// redirect to referer
				$this->redirect($this->referer());
			
			} else {
				$this->Session->setFlash(__d('lil_blogs', 'Uh oh, we weren\'t able to save your comment.', true), 'error');
				
				// redirect to referer
				$this->redirect($this->referer());
			}
		}
		
		if ($this->RequestHandler->prefers('rss') == 'rss') {
			Configure::write('debug', 0);
			$this->set('channel', array(
				'title'       => $blog['Blog']['name'], 
				'description' => $blog['Blog']['description']
			));
		}
	}
/**
 * admin_index method
 *
 * @param int $blogid
 * @access public
 * @return void
 */
	function admin_index() {
		// extract blog data from params
		$blog_name = $this->_extractBlog();
		$blog_id = $this->_extractBlogId();
		
		// check if blog's ok
		$blog = null;
		if (isset($this->Area) && !(($blog_name && $blog = $this->Area->findByShortName($blog_name)) || 
			($blog_id && $blog = $this->Area->findById($blog_id))))
		{
			return $this->error404();
		}
		
		if (!empty($blog) || (is_null($blog_id) && Configure::read('LilBlogs.allowEmptyBlog'))) {
			$params = array(
				'limit'   => 10,
				'order'   => 'Post.created DESC',
			);
			
			if (Configure::read('LilBlogs.blogAssociation') || !empty($blog)) {
				if (!$blog_field = Configure::read('LilBlogs.blogAssociation.foreignKey')) {
					$blog_field = 'blog_id';
				}
				$params['conditions']['Post.' . $blog_field] = $blog[$this->Area->alias]['id'];
			}
			if (Configure::read('LilBlogs.blogAssociation')) {
				$params['contain'] = array('Author');
			}
			
			if (!empty($this->params['url']['filter'])) $filter = $this->params['url']['filter'];
			
			$this->paginate = array_merge_recursive($params, $this->Post->filter($filter));
			
			$data = $this->paginate('Post');
			$this->set(compact('data', 'filter', 'blog'));
		} else {
			$this->error404();
		}
	}
/**
 * admin_add method
 *
 * @access public
 * @return void
 */
	function admin_add() {
		$this->setAction('admin_edit');
	}
/**
 * admin_edit method
 *
 * @param int $id
 * @access public
 * @return void
 */
	function admin_edit($id = null) {
		// extract blog data from params
		$blog_param_name = $this->_extractBlog();
		$blog_param_id = $this->_extractBlogId();
		
		// check if blog's ok
		$blog = null; $blog_id = null;
		if (isset($this->Area) && (($blog_param_name && $blog = $this->Area->findByShortName($blog_param_name)) || 
			($blog_param_id && $blog = $this->Area->findById($blog_param_id)))) {
				$blog_id = $blog[$this->Area->alias]['id'];
		}
		
		
		if (!empty($this->data)) {
			$data = $this->callPluginHandlers('before_save_post', array('data' => $this->data));
			if ($data) {
				if ($this->Post->saveAll($data['data'])) {
					$this->setFlash(__d('lil_blogs', 'Post has been saved.', true));
					
					$this->doRedirect(array(
						'admin'  => true,
						'action' => 'index',
						$this->data['Post']['blog_id']
					));
				} else {
					$this->setFlash(__d('lil_blogs', 'Please verify that the information is correct.', true), 'error');
				}
			}
		} else if (
			!empty($id) && 
			$this->data = $this->Post->find('first', array(
				'conditions' => array('Post.id' => $id),
				'contain'    => array_merge(
					(empty($this->Post->belongsTo['Author']) ? array() : array('Author')),
					(empty($this->Post->hasAndBelongsToMany['Category']) ? array() : array('Category'))
				)
			))
		) {
			// do nothing here
		} else if (empty($id) && !empty($blog_id) || (is_null($blog_id) && Configure::read('LilBlogs.allowEmptyBlog'))) {
			$this->request->data['Post']['blog_id'] = $blog_id;
		} else {
			return $this->error404();
		}
		
		$this->setupRedirect();
		
		if (!Configure::read('LilBlogs.noCategories')) {
			$conditions = array();
			if (!Configure::read('Lil.noAreas')) {
				$conditions['Category.blog_id'] = $blog_id;
			}
			
			// generate parent list
			$categories = array();
			if (Configure::read('LilBlogs.categoryAssociation')) {
				$categories = $this->Category->generateTree(
					'simple',
					array(
						'conditions' => $conditions,
						'recursive'  => -1
					)
				);
			}
			$this->set(compact('categories'));
		}
		
		$authors = $this->User->find(
			'list',
			array(
				'fields' => array('id', Configure::read('Lil.userDisplayField')),
				'recursive' => -1
			)
		);
		$this->set(compact('authors'));
	}
/**
 * admin_delete method
 *
 * @param int $id
 * @access public
 * @return void
 */
	function admin_delete($id = null) {
		$this->Post->recursive = -1;
		if (is_numeric($id) && $data = $this->Post->findById($id)) {
			$this->Post->delete($id);
			$this->Session->setFlash(__d('lil_blogs', 'Post has been deleted.', true));
			$this->redirect($this->referer());
		} else {
			$this->error404();
		}
	}
/**
 * _clean method
 *
 * @param mixed $data
 * @access private
 * @return void
 */
	function _clean(&$data) {
		$data['body'] = $this->kses5Clean($data['body']);
	}
/**
 * _extractBlog method
 *
 * Extract blog's slug form parameters.
 *
 * @access private
 * @return void
 */
	function _extractBlog($lookup = array('params', 'named', 'pass', 'config')) {
		if (!empty($this->params['blog']) && in_array('params', $lookup)) {
			return $this->params['blog'];
		}
		if (!empty($this->params['named']['blog']) && in_array('named', $lookup)) {
			return $this->params['named']['blog'];
		}
		if (!empty($this->params['pass'][0]) && in_array('pass', $lookup)) {
			return $this->params['pass'][0];
		}
		if (($blog_name = Configure::read('LilBlogs.defaultBlog')) && in_array('config', $lookup)) {
			return $blog_name;
		}
		return false;
	}
/**
 * _extractBlogId method
 *
 * Extract blog's id form parameters.
 *
 * @access private
 * @return void
 */
	function _extractBlogId($lookup = array('params', 'named', 'pass', 'config')) {
		if (!empty($this->params['blogid']) && in_array('params', $lookup)) {
			return $this->params['blogid'];
		}
		if (!empty($this->params['named']['blogid']) && in_array('named', $lookup)) {
			return $this->params['named']['blogid'];
		}
		if (!empty($this->params['named']['blog_id']) && in_array('named', $lookup)) {
			return $this->params['named']['blog_id'];
		}
		if (!empty($this->params['pass'][1]) && in_array('pass', $lookup)) {
			return $this->params['pass'][0];
		}
		return false;
	}
/**
 * _extractPost method
 *
 * Extract post form parameters.
 *
 * @access private
 * @return void
 */
	function _extractPost($lookup = array('params', 'named', 'pass', 'config')) {
		if (!empty($this->params['postid'])  && in_array('params', $lookup)) {
			return $this->params['postid'];
		}
		if (!empty($this->params['post'])  && in_array('params', $lookup)) {
			return $this->params['post'];
		}
		if (!empty($this->params['slug'])  && in_array('params', $lookup)) {
			return $this->params['slug'];
		}
		if (!empty($this->params['named']['postid'])  && in_array('named', $lookup)) {
			return $this->params['named']['postid'];
		}
		if (!empty($this->params['named']['post'])  && in_array('named', $lookup)) {
			return $this->params['named']['post'];
		}
		if (!empty($this->params['named']['slug'])  && in_array('named', $lookup)) {
			return $this->params['named']['slug'];
		}
		if (!empty($this->params['pass'][0]) && in_array('pass', $lookup)) {
			return $this->params['pass'][0];
		}
	}
}